<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\UserModel;
use App\Repositories\UserRepository;
use App\Validations\UserValidation;
use HttpException\ClientError\BadRequestException;
use HttpException\ClientError\ConflictException;
use HttpException\ClientError\NotFoundException;

class UserService extends BaseService
{
    /**
     * Obtiene una instancia de las reglas de validación.
     */
    private function userValidation(): UserValidation
    {
        return new UserValidation;
    }

    /**
     * Obtiene una instancia del repositorio.
     */
    private function userRepository(): UserRepository
    {
        return new UserRepository;
    }

    /**
     * Registra la información de un nuevo usuario.
     */
    public function register(array $data): UserModel
    {
        $fields = array_keys($data);
        $userValidation = $this->userValidation();

        // Valida la información del usuario.
        $this->app()->gump()->validation_rules($userValidation->getRules($fields, true));
        $this->app()->gump()->filter_rules($userValidation->getFilters($fields));

        $data = $this->app()->gump()->run($data);

        // Comprueba si existen errores de validación.
        if ($this->app()->gump()->errors()) {
            throw new BadRequestException('La información del usuario es incorrecta');
        }

        $userRepository = $this->userRepository();

        // Comprueba que los campos sean únicos.
        foreach (['username', 'email'] as $field) {
            if ($userRepository->findIdByColumn($field, $data[$field])) {
                throw new ConflictException(sprintf('El campo "%s" debe ser único', $field));
            }
        }

        unset($data['password_confirm']);

        return $userRepository->insert($data);
    }

    /**
     * Obtiene la información detallada de un usuario.
     */
    public function getDetailsById(string $id): UserModel
    {
        // Valida el id del usuario.
        $this->app()->gump()->validation_rules($this->userValidation()->getRules('id', true));
        $this->app()->gump()->run(['id' => $id]);

        // Comprueba si existen errores de validación.
        if ($this->app()->gump()->errors()) {
            throw new BadRequestException('El identificador del usuario es incorrecto');
        }

        // Consulta la información del usuario.
        $user = $this->userRepository()->findByIdWithDetails($id);

        // Comprueba si existe el usuario.
        if (empty($user)) {
            throw new NotFoundException('No se encontró la información del usuario');
        }

        return $user;
    }
}
